package com.sunday.common.validation.annotation;

import com.sunday.common.core.enums.ErrorCodeEnum;
import com.sunday.common.core.validation.annotation.ErrorCodeAttribute;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;

/**
 * @Description: 开启分布式锁
 * <p>
 * 默认为排他锁策略
 * 如果需要其他策略请自行调用 RedissonClient 进行操作， 不要添加此备注
 * <p>
 * 例子： javax.validation.constraints.NotBlank
 * @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理,
 * 所以注解类型信息也会被包括在生成的文档中，是一个标记注解，没有成员。
 * @Constraint(validatedBy = { })
 * 自定义验证注解,为什么默认注解中，不添加任何值，并且可以进行验证，请查看下面的源代码
 * org.hibernate.validator.internal.metadata.core.ConstraintHelper
 * @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
 * 说明了Annotation所修饰的对象范围：Annotation可被用于 packages、types（类、接口、枚举、Annotation类型）、类型成员（方法、构造方法、成员变量、枚举值）、
 * 方法参数和本地变量（如循环变量、catch参数）。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
 * 用于描述类、接口(包括注解类型) 或enum声明 Class, interface (including annotation type), or enum declaration
 * TYPE
 * 用于描述域 Field declaration (includes enum constants)
 * FIELD
 * 用于描述方法 Method declaration
 * METHOD
 * 用于描述参数 Formal parameter declaration
 * PARAMETER
 * 用于描述构造器 Constructor declaration
 * CONSTRUCTOR
 * 用于描述局部变量 Local variable declaration
 * LOCAL_VARIABLE
 * Annotation type declaration
 * ANNOTATION_TYPE
 * 用于描述包 Package declaration
 * PACKAGE
 * 用来标注类型参数 Type parameter declaration
 * TYPE_PARAMETER
 * 能标注任何类型名称 Use of a type
 * TYPE_USE
 * @Retention(RUNTIME) 作用是定义被它所注解的注解保留多久，一共有三种策略，定义在RetentionPolicy枚举中.
 * 从注释上看：
 * source：注解只保留在源文件，当Java文件编译成class文件的时候，注解被遗弃；被编译器忽略
 * class：注解被保留到class文件，但jvm加载class文件时候被遗弃，这是默认的生命周期
 * runtime：注解不仅被保存到class文件中，jvm加载class文件之后，仍然存在
 * @Repeatable(List.class) 当我们需要重复使用某个注解时，希望利用相同的注解来表现所有的形式时，我们可以借助@Repeatable注解。
 * https://www.jianshu.com/p/6db80f2c2b6f
 * https://blog.csdn.net/weixin_42245133/article/details/99678509
 * @AliasFor 注解属性声明别名
 * https://blog.csdn.net/weixin_43564627/article/details/93871075/
 * @Inherited 当以后我们在定义一个作用于类的注解时候，如果希望该注解也作用于其子类，那么可以用@Inherited 来进行修饰.
 * https://blog.csdn.net/sunnyzyq/article/details/119736442
 * <p>
 * https://blog.csdn.net/shuixiou1/article/details/80282620
 * 注解继承的说明
 * 1、首先要想Annotation能被继承，需要在注解定义的时候加上@Inherited，并且如果要被反射应用的话，就需要还有个事@Retention(RetentionPolicy.RUNTIME)标识
 * 2、JDK文档中说明的是:只有在类上应用Annotation才能被继承，而实际应用结果是:除了类上应用的Anntation能被继承外，没有被重写的方法的Annotation也能被继承;
 * 3、当方法被重写后，Annotation不会被继承
 * 4、Annotation的继承能应用在接门上
 *
 * <p>
 * 如果要使用OpenDistributedLockValidator ->  @Constraint(validatedBy = {OpenDistributedLockValidator.class })
 * @Author: zsy
 * @Create: 2022/10/20 15:15
 */
@ErrorCodeAttribute
@Inherited
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {OpenDistributedLockValidator.class})
public @interface OpenDistributedLock {

    /**
     * redis key 前缀
     */
    String value();

    /**
     * A0_502(ErrorClassifyEnum.A + "0502","请求并发数超出限制")
     */
    @AliasFor(annotation = ErrorCodeAttribute.class)
    ErrorCodeEnum errorCodeEnum() default ErrorCodeEnum.A0_502;

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}
